#include <math.h>
#include <allegro.h>

#define PI (atan(1)*4)

float rotation = PI*0.25;
float elevation = 1.1;
float zoom = 30.0;
float right_x, right_y;
float front_x, front_y;
float up_x, up_y; 

float default_sprite_width = 1.5;
float default_sprite_height = 3.0;

float x, y, z, screen_x, screen_y;

float sprite_x = 3;
float sprite_y = 3;
float sprite_width, sprite_height;

int i;

PALETTE palette;
BITMAP *buffer;
BITMAP *image;

void make_poly_dot(int *poly, int index, float x, float y)
{
  z = (sin(x/2) + cos(y/2)) * 2;
  screen_x = x * right_x + y * front_x + z * up_x;
  screen_y = x * right_y + y * front_y + z * up_y;
  screen_x += SCREEN_W * 0.5;
  screen_y += SCREEN_H * 0.5;
  poly[index] = (int)floor(screen_x);
  poly[index+1] = (int)floor(screen_y); 
}

void make_poly(int *poly, float x, float y)
{
  make_poly_dot(poly, 0, x-0.5, y-0.5);
  make_poly_dot(poly, 2, x-0.5, y+0.5);
  make_poly_dot(poly, 4, x+0.5, y+0.5);
  make_poly_dot(poly, 6, x+0.5, y-0.5);
  make_poly_dot(poly, 8, x-0.5, y-0.5);
}

int main(void)
{

  if (allegro_init() != 0)
    return 1;
  install_timer();
  install_keyboard();

  set_color_depth(32);

  if (set_gfx_mode(GFX_AUTODETECT_WINDOWED, 800, 600, 0, 0) != 0) 
  {
   if (set_gfx_mode(GFX_SAFE, 320, 200, 0, 0) != 0)
    {
      set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
      allegro_message("Unable to set any graphic mode\n%s\n", allegro_error);
      return 1;
    }
  }
  buffer = create_bitmap(SCREEN_W, SCREEN_H);

  image = load_bitmap("woman.bmp", palette);

  
  while (!key[KEY_ESC])
  {
    clear_bitmap(buffer);

    if (key[KEY_4_PAD]) rotation += 0.01;
    if (key[KEY_6_PAD]) rotation -= 0.01;    
    if (key[KEY_8_PAD]) elevation += 0.01;
    if (key[KEY_2_PAD]) elevation -= 0.01;    
    if (key[KEY_EQUALS] || key[KEY_PLUS_PAD]) zoom *= 1.01;    
    if (key[KEY_MINUS] || key[KEY_MINUS_PAD]) zoom *= 0.99;

    if (key[KEY_UP] && key[KEY_LEFT]) {
      sprite_x -= 1;
    }
    if (key[KEY_UP] && key[KEY_RIGHT]) {
      sprite_x += 1;
    }
    if (key[KEY_DOWN] && key[KEY_LEFT]) {
      sprite_y += 1;
    }
    if (key[KEY_DOWN] && key[KEY_LEFT]) {
      sprite_y -= 1;
    }

    if (key[KEY_UP]) {
      sprite_x -= 1;
      sprite_y -= 1;
    }
    if (key[KEY_DOWN]) {
      sprite_x += 1;
      sprite_y += 1;
    }
    if (key[KEY_LEFT]) {
      sprite_x -= 1;
      sprite_y += 1;
    }
    if (key[KEY_RIGHT]) {
      sprite_x += 1;
      sprite_y -= 1;
    }

    if (sprite_x < -15.0) sprite_x = -15.0;
    if (sprite_x >  15.0) sprite_x =  15.0;
    if (sprite_y < -15.0) sprite_y = -15.0;
    if (sprite_y >  15.0) sprite_y =  15.0;

    /* precalculated vectors */
    right_x = cos(rotation) * zoom;
    right_y = sin(rotation) * cos(elevation) * zoom;
    front_x = -sin(rotation) * zoom;
    front_y = cos(rotation) * cos(elevation) * zoom;
    up_x = 0.0 * zoom;
    up_y = sin(elevation) * zoom;

    sprite_width = default_sprite_width * zoom;
    sprite_height = default_sprite_height * zoom;

    /* painting the ground */
    for (x=-15.0; x<=15.0; x+=1.0)
    {
      for (y=-15.0; y<=15.0; y+=1.0)
      {

        /* drawing the ground */
        int poly[10];
        make_poly(poly, x, y);

        polygon(buffer, 5, poly, makecol(0,200,0));

        for (i = 2; i < 10; i+=2)
        {
          line(buffer,
               poly[i-2],
               poly[i-1],
               poly[i],
               poly[i+1],
               makecol(0,100,0));
        }

        /* drawing the sprite */
        if (sprite_x == x && sprite_y == y)
        {
          z = (sin(x/2) + cos(y/2)) * 2;

          /* difference between the ground and the character foot */
          z += 0.2;

          screen_x = x * right_x + y * front_x + z * up_x;
          screen_y = x * right_y + y * front_y + z * up_y; 

          screen_x -= (sprite_width * 0.5);
          screen_y -= sprite_height;
          BITMAP *stretched;
          stretch_sprite(buffer, image,
                        (int)floor(screen_x + SCREEN_W * 0.5), 
                        (int)floor(screen_y + SCREEN_H * 0.5), 
                        sprite_width, sprite_height);
        }
      }
    }



    textprintf_ex(buffer, font, 10, 10, makecol(255, 255, 255), -1, 
                  "rotation.: % 06.2f", rotation);
    textprintf_ex(buffer, font, 10, 20, makecol(255, 255, 255), -1, 
                  "elevation: % 06.2f", elevation);

    blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
    rest(20);
  }

  destroy_bitmap(buffer);
  return 0;
}

END_OF_MAIN();

